package ru.compft.aop.profiling;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * User: ASUS
 * Date: 21.10.12
 * Time: 11:38
 * Компонент для профилирования
 */
@Component
@Aspect
public class WebLayerProfiler {
    private static final Logger logger = LoggerFactory.getLogger(WebLayerProfiler.class);

    @Before(value = "ru.compft.aop.SystemArchitecture.inWebLayer()")
    public void doWebLayerBefore() {
        System.out.println("WebLayerProfiler doWebLayerBefore");
    }

    @Before(value = "ru.compft.aop.SystemArchitecture.webOperation()")
    public void doWebOperationBefore() {
        System.out.println("WebLayerProfiler doWebOperationBefore");
    }

    @Around("ru.compft.aop.SystemArchitecture.inWebLayer()")
    public Object doWebLayerProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("WebLayerProfiler doWebLayerProfiling = " + pjp);
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

    @Around("ru.compft.aop.SystemArchitecture.webOperation()")
    public Object doWebOperationProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("WebLayerProfiler doWebOperationProfiling = " + pjp);
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        return retVal;
    }

    /**
     * After (finally) advice runs however a matched method execution exits
     */
    @After("ru.compft.aop.SystemArchitecture.inWebLayer()")
    public void doWebLayerMethodAfter() {
        System.out.println("WebLayerProfiler doWebLayerMethodAfter");
    }

    @After("ru.compft.aop.SystemArchitecture.webOperation()")
    public void doWebOperationMethodAfter() {
        System.out.println("WebLayerProfiler doWebOperationMethodAfter");
    }

    /**
     * Sometimes you need access in the advice body to the actual value that was returned
     *
     * @param retVal
     */
    @AfterReturning(pointcut = "ru.compft.aop.SystemArchitecture.inWebLayer()",
            returning = "retVal")
    public void doWebLayerAfterReturning(Object retVal) {
        System.out.println("WebLayerProfiler doWebLayerAfterReturning. Obj = " + retVal);
        // ...
    }

    @AfterReturning(pointcut = "ru.compft.aop.SystemArchitecture.webOperation()",
            returning = "retVal")
    public void doWebOperationAfterReturning(Object retVal) {
        System.out.println("WebLayerProfiler doWebOperationAfterReturning. Obj = " + retVal);
        // ...
    }

    /**
     * After throwing advice runs when a matched method execution exits by throwing an exception
     */
    @AfterThrowing("ru.compft.aop.SystemArchitecture.inWebLayer()")
    public void doWebLayerAfterThrowing() {
        System.out.println("WebLayerProfiler doWebLayerAfterThrowing");
        // ...
    }

    @AfterThrowing("ru.compft.aop.SystemArchitecture.webOperation()")
    public void doWebOperationAfterThrowing() {
        System.out.println("WebLayerProfiler doWebOperationAfterThrowing");
        // ...
    }

    /**
     * Often you want the advice to run only when exceptions of a given type are thrown, and you also often need access
     * to the thrown exception in the advice body
     *
     * @param ex
     */
    @AfterThrowing(pointcut = "ru.compft.aop.SystemArchitecture.inWebLayer()",
            throwing = "ex")
    public void doWebLayerAfterThrowing(Exception ex) {
        System.out.println("WebLayerProfiler doWebLayerAfterThrowing. Ex = " + ex);
        // ...
    }

    @AfterThrowing(pointcut = "ru.compft.aop.SystemArchitecture.webOperation()",
            throwing = "ex")
    public void doWebOperationAfterThrowing(Exception ex) {
        System.out.println("WebLayerProfiler doWebOperationAfterThrowing. Ex = " + ex);
        // ...
    }
}
